using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Microsoft.DirectX.Direct3D;
using Lizk.SimpleHUD;
using Lizk.Utilities;

namespace SharpMedia.MDX
{
    public class MDXImage : IDisposable
    {
        private Device device;
        private Texture texture;
        private string textureFile;
        private Size maxSize;
        private Rectangle textureBounds;
        private bool isLoaded = false;
        
        private bool disposed = false;
        public event EventHandler TextureLoaded;
        public string TexturePath { get { return textureFile; } }


        public bool IsLoaded { get { return isLoaded; } }

        public Rectangle TextureSize { get { return textureBounds; } }

        public Texture Texture { get { return texture; } set { texture = value; } }

        public bool Disposed { get { return disposed; } }

        private MDXImage(Device d, string file, EventHandler eh)
        {
            device = d;
            textureFile = file;
            TextureLoaded += eh;
        }

        ~MDXImage()
        {
            Dispose();
        }


        public void Dispose()
        {
            if (!disposed)
            {
                if (texture != null && !texture.Disposed)
                {
                    texture.Dispose();
                    texture = null;
                }
                disposed = true;
            }
        }

        public static class MDXImageLoader
        {
            private static bool theEnd = false;
            private static Queue<MDXImage> loadQueue = new Queue<MDXImage>();

            private static Thread loadWorker = null;

            static MDXImageLoader()
            {
                loadWorker = new Thread(new ThreadStart(ProcessQueue));
                loadWorker.Name = "MDXImage Worker";
                loadWorker.Start();
                Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
            }

            static void Application_ApplicationExit(object sender, EventArgs e)
            {
                theEnd = true;
                Monitor.Enter(queueLock);
                loadQueue.Clear();
                Monitor.PulseAll(queueLock);
                Monitor.Exit(queueLock);
            }
            static object queueLock = new object();
            public static MDXImage FromFile(Device device, string file, EventHandler eh, Size maxSize)
            {


                Monitor.Enter(queueLock);
                MDXImage image = new MDXImage(device, file, eh);
                image.maxSize = maxSize;

                //ThreadPool.QueueUserWorkItem(new WaitCallback(LoadTexture), image);
                
                loadQueue.Enqueue(image);
                Monitor.PulseAll(queueLock);
                Monitor.Exit(queueLock);
                return image;
            }

            private static void ProcessQueue()
            {
                while (true)
                {
                    Monitor.Enter(queueLock);
                    while (loadQueue.Count == 0)
                    {
                        if (theEnd)
                        {
                            Monitor.Exit(queueLock);
                            return;
                        }
                        else
                        {
                            Monitor.Wait(queueLock);
                        }
                    }


                    MDXImage image = loadQueue.Dequeue();
                    Monitor.PulseAll(queueLock);
                    Monitor.Exit(queueLock);

                    if (!image.isLoaded)
                        LoadTexture(image);
                }
            }

            private static int Pow2Adjust(int i)
            {
                return (int)Math.Pow(2, Math.Round(Math.Log(i, 2)));
            }

            private static void LoadTexture(MDXImage image)
            {
                if (string.IsNullOrEmpty(image.textureFile))
                    return;

                using (FileStream fs = File.OpenRead(image.textureFile))
                {
                    try
                    {
                        ImageInformation i = TextureLoader.ImageInformationFromStream(fs);
                        fs.Seek(0, SeekOrigin.Begin);

                        if (image.device.DeviceCaps.TextureCaps.SupportsPower2)
                        {
                            RectangleS size = HUDImage.ResizeConstrained(true, new SizeS(i.Width, i.Height), new SizeS(Pow2Adjust(i.Width), Pow2Adjust(i.Height)));
                            image.textureBounds = new Rectangle(0, 0, (int)size.Width, (int)size.Height);
                        }

                        image.texture = TextureLoader.FromStream(image.device, fs, i.Width, i.Height, 2, Usage.None, Format.A8R8G8B8, Pool.Managed, Filter.Linear, Filter.Linear, 0);
                        image.textureBounds = new Rectangle(0, 0, i.Width, i.Height);
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine("Image Not loaded: " + e.Message);
                    }
                }

                if (image.texture != null)
                {
                    image.isLoaded = true;
                    if (image.TextureLoaded != null)
                        image.TextureLoaded(image, null);
                }
            }


        }
    }




}